package com.franklin.java.completion.method.entity;

import com.franklin.java.completion.CompletionOrder;
import com.franklin.java.completion.MyInsertHandler;
import com.franklin.java.completion.method.JavaMethodCommentCompletionContributor;
import com.franklin.java.configuration.sql.completion.CompletionSettingState;
import com.franklin.java.entity.sql.ColumnInfo;
import com.franklin.java.utils.CompletionUtils;
import com.franklin.java.utils.EntityClassHelper;
import com.franklin.java.utils.PsiUtils;
import com.franklin.plugins.common.collection.PrettyArrayList;
import com.franklin.plugins.common.utils.DataCheckUtils;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * java实体属性注释提示
 *
 * @author Franklin
 * @since 2021/9/3 15:58
 */
public class JavaEntityPropertiesCompletionContributor extends JavaMethodCommentCompletionContributor {

    @Override
    public boolean isCorrectCompletionParameter(@NotNull CompletionParameters parameters) {
        Project project = parameters.getPosition().getProject();
        if (CompletionSettingState.isShowEntityComment(project)){
            return super.isCorrectCompletionParameter(parameters);
        }
        return false;
    }

    @Override
    public List<LookupElement> getLookupElements(CompletionParameters parameters) {
        try {
            List<LookupElement> systemElementList = getSetMethodElements.get();
            if (DataCheckUtils.isEmpty(systemElementList)) {
                return Collections.emptyList();
            }
            String psiType = callingElementType.get();
            PsiClass targetClass = PsiUtils.findClass(getCurrentProject(), parameters.getOriginalFile().getVirtualFile().getPath(), psiType);;

            if (Objects.isNull(targetClass)) {
                return Collections.emptyList();
            }

            List<ColumnInfo> columnInfos = EntityClassHelper.resolveColumnInEntity(targetClass, "");
            if (DataCheckUtils.isEmpty(columnInfos)) {
                return Collections.emptyList();
            }

            List<LookupElement> result = new PrettyArrayList<>();

            Map<String, ColumnInfo> columnNameColumnMap = columnInfos.stream()
                    .collect(Collectors.toMap(ColumnInfo::getColumnName, Function.identity()));

            Class<LookupElementDecorator> lookupElementDecoratorClass = LookupElementDecorator.class;
            Field myDelegate = lookupElementDecoratorClass.getDeclaredField("myDelegate");
            myDelegate.setAccessible(true);

            for (LookupElement lookupElement : systemElementList) {
                String lookupString = lookupElement.getLookupString();
                String filedName = EntityClassHelper.resolveFiledName(lookupString);
                if (DataCheckUtils.isNotEmpty(filedName)) {
                    try {
                        LookupElementDecorator decorator = (LookupElementDecorator) myDelegate.get(lookupElement);
                        Optional.ofNullable(columnNameColumnMap.get(filedName))
                                .ifPresent(columnInfo -> {
                                    String type = PsiUtils.getSimpleClassName(columnInfo.getJavaType());
                                    String tailText = "()  " + columnInfo.getComment();
                                    PsiElement psiElement = lookupElement.getPsiElement();
                                    if (psiElement instanceof PsiMethod){
                                        PsiMethod psiMethod = (PsiMethod) psiElement;
                                        tailText = resolveMethodLookupElementTailText(psiMethod,columnInfo.getComment());
                                        type = resolveMethodLookupElementType(psiMethod,type);
                                    }
                                    LookupElement newLookupElement = CompletionUtils.getLookElement(
                                            lookupString,
                                            type,
                                            tailText,
                                            new GetMethodInsertHandler(decorator)
                                    );
                                    result.add(newLookupElement);
                                    addHandledElement(lookupElement);
                                });
                    } catch (Exception e) {

                    }
                }
            }

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    @Override
    public CompletionOrder getOrder() {
        return CompletionOrder.HIGH;
    }

    private static class GetMethodInsertHandler extends MyInsertHandler {

        private LookupElementDecorator delegate;

        private GetMethodInsertHandler(LookupElementDecorator delegate) {
            this.delegate = delegate;
        }

        @Override
        public void handleInsert(@NotNull InsertionContext context, @NotNull LookupElement item) {
            delegate.handleInsert(context);
            context.commitDocument();
            super.handleInsert(context, item);
        }
    }
}
